#!/bin/sh
#*  @brief        文件内容操作有关的

# 创建随机文件
function file-make-random () {
    local OUTPUT_DIR=~/test
    ## 反复读写15次
    for j in {1..15};do
        rm  ${OUTPUT_DIR} -rf
        mkdir ${OUTPUT_DIR} -p
        echo $j
        ## 每次 创建 1000个小文件
        for i in {1..1000};do
            dd if=/dev/random of=${OUTPUT_DIR}/${i}.log bs=16k count=1 &>/dev/null
            sync
        done
    done
    return

#   16Kb  * 100 = 1.6MB
#   1000           16MB
#   10000         160MB
#   100000       1600MB   1.6Gb
#   1000000     16000MB    16GB
#   10000000   160000MB   160GB
#   20000000   320000MB   320GB
}

## 清空文件
function file-make-empty () {
    if [ -z "$1" ]; then
        return
    fi

    if [ -f /dev/null ]; then
        cp /dev/null $1
        return
    fi
    rm $1  > /dev/null  2>&1
    touch $1
}

## 添加指定的文本，将文件分为2部分
function file-make-2parts ()
{
    # 输入文件
    local FILE1=$1
    # 输出文件1
    local PART1=$2
    # 输出文件2
    local PART2=$3
    # 用于分割的文本（需要在文件中已经存在）
    local SPLIT=$4

    if [ ! -e $FILE1 ]; then
        echo "$FILE1 is not exsit"
        return
    fi
    echo '' > $PART1
    echo '' > $PART2
    local MODEM=1
    cat $1 |while read line
    do
        if [ "$line" = $SPLIT ]; then
            MODEM=2
        fi

        if [ $MODEM -eq 1 ]; then
            echo "$line"  >> $PART1
        else
            echo "$line"  >> $PART2
        fi
    done
}

# 把文件按每行多少个字符进行打印（常用于HEX文件）
# e.g. : file-cat-block-per-line a.hex 32
function file-cat-block-per-line() {
    # 每行显示多少个字符
    local __FILE=$1
    local __COUNT=$2
    sed "s/.\{${__COUNT}\}/&\n/g" $__FILE
}


# 把文件内容统统打印为一行
function file-cat-as-oneline() {
    local fin=$1
    if [ -z "$fin" ]; then
        return 1
    fi
    cat $fin | while read line;do echo -n "$line" ;done
    echo ""
}

# 将多个空行替换为一个空行
function file-trim-mutliple-empty-lines() {
    local fin=$1
    local fout=$2

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    # 将空白行替换成纯空行，再将连续多给纯空行合并成一个空行
    awk '!NF{$0="\n"}1' $fin  | sed '/^$/N;/^\n$/D' > $fout.tmp
    mv -f $fout.tmp $fout
}

# 替换tab为4个空格
function file-tab-to-4space () {
    local fin=$1
    local fout=$2

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    ## 1、 通过 sed 实现
    ##^I是在命令行中输入<Ctrl-V><Tab>来键入的
    #sed 's/	/    /g' $fin  > $fout.tmp
    ## 2、 通过 expand 实现
    expand -t 4 $fin > $fout.tmp

    mv -f  $fout.tmp $fout
}

# 替换4个空格为tab
function file-4space-to-tab () {
    local fin=$1
    local fout=$2

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    unexpand -t 4 $fin > $fout.tmp

    mv -f  $fout.tmp $fout
}

# --------------------------------------------------------------------------- #
# 仅在包含指定文本的行内做替换
# Parameter1    : 文件名
# parameter2~N-2: 文本必须包含的关键字，允许N个
# parameterN-1  : 需要替换的文本
# parameterN    : 替换以后的新文本
# return: 8: 错误参数或不满足执行条件
# --------------------------------------------------------------------------- #
function file-replace-string-only-in-matched-line()
{
    local file_name="$1"
    # 从第2个参数到倒数第3个参数
    local match_part="$2" # 允许支持多个匹配条件
    # 倒数第2个参数
    local oldtext="$3"
    # 倒数第1个参数(最后一个参数)
    local newtext="$4"

    local help_info=""
    help_info=$(cat << EOF
 file  pattern1 [pattern2...]  old-text  new-text
 e.g :
     file-replace-string-only-in-matched-line main.c 'int main('      'int' "void"
     将 main.c 中的 包含 'int main(' 的行，中的'int'改为'void'

     file-replace-string-only-in-matched-line main.c 'int'  '=' ";"  'int' 'unsigned int'
     将 main.c 中的 同时包含 'int'与';' 的行，中的'int'改为'unsigned int'
EOF
)
    if [ $# -lt 4 ]; then
        echo "$help_info"; return 8
    fi

    local patters_cmd="grep -n \"$oldtext\" | "
    # 分离 第2个参数~倒数第3个参数为一组；最后2个参数为一组
    shift
    until [ $# -le 2 ];
    do
        cur=`echo " grep \"$1\" |"`
        patters_cmd=`echo -n "$patters_cmd $cur"`
        shift
    done
    oldtext="$1"
    newtext="$2"

    # oldtext不允许为空，而允许newtext为空
    if [ -z "$oldtext" ];then
        echo "$help_info"; return 8
    fi

    # 把变量当成命令来执行
    ########## cat $file_name| grep -n $2 [| grep ...] |  awk -F: '{print\$1}'"
    local cmd="cat $file_name| $patters_cmd  awk -F: '{print\$1}'"
    local cmd_ret_lines=`echo ${cmd}|awk '{run=$0;system(run)}'`

    #for line_no in `cat $file_name| grep "$oldtext" -n | grep "$match_part"  | awk -F: '{print$1}'`
    for line_no in `echo $cmd_ret_lines`
    do
        # 获取对应的行文本
        CONTEXT=`sed -n "${line_no}p" $file_name`
        # 在行文本内做替换，得到新的行文本
        NEW_TEXT=`_replace_string "$CONTEXT" "${oldtext}" "${newtext}"`
        echo "Change [$CONTEXT] to [$NEW_TEXT]"
        # 将指定行精确替换为 新的行文本
        file-replace-the-line-string "$file_name" ${line_no} "$NEW_TEXT"
    done
}

## 删除含有关键字的行
function file-delete-line-contain-string() {
    local file="$1"
    local string="$2"
    if [ ! -f $file ]; then
        return
    fi

    if [ -z "$string" ]; then
        return
    fi
    sed "/$(sed 's#/#\\/#g'<<<$string)/d" -i $file
}

# 去掉匹配行以及此后的内容
function file-remove-matched-line-and-balabal() {
    local fin="$1"
    local old="$2"

    if [ ! -f "$fin" ]; then
        echo "file.in remove-str"
        return 1
    fi
    if [ -z "$old" ]; then
        echo "file.in remove-str"
        return 1
    fi
    bak $fin
    local oldt=`echo $old| sed 's:\/:\\\/:g'`
    bash <<EOF
    sed -i  '/$oldt/,\$d' $fin
EOF
}

# 去掉所有的空行
function file-remove-all-empty-lines() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed '/^\s*$/d' $fin > $fout.tmp
    mv -f $fout.tmp $fout
}

# 去掉所有的 纯数字行（有些markdown复制下来会有一些行文本，如下）
# ```bash
# echo "e.g."
# 1
# ```
function file-remove-all-pure-0-9() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed -r '/^[0-9]{1,}$/d' $fin > $fout.tmp
    mv -f $fout.tmp $fout
}

# 去掉所有的 纯字母行
function file-remove-all-pure-A-z() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed -r '/^[A-Za-z]{1,}$/d' $fin > $fout.tmp
    mv -f $fout.tmp $fout
}

# 去掉行首的空白符
function file-remove-all-space-at-begin-of-lines() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed 's/^[ \t]*//g' $fin > $fout.tmp
    mv -f $fout.tmp $fout
}

# 移除行尾的空白符
function file-remove-all-space-at-end-of-lines() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed 's/[ \t]*$//g' $fin > $out.tmp
    mv -f $fout.tmp $fout
}

## 去除 CSDN 有关行的
function file-remove-csdn ()
{
    if [ ! -e $1 ]; then
        return
    fi
    sed -i '/————————————————/d' $1
    sed -i '/版权声明：本文为CSDN博主/d' $1
    sed -i '/版权协议，转载请附上原文出处链接及本声明/d' $1
    sed -i '/原文链接：https:\/\/blog.csdn.net\//d' $1
}

# 替换文本（请不要直接使用此函数）
_replace_string(){
    local CONTEXT="$1"
    local old="$2"
    local new="$3"

    local oldt=`echo "$old"| sed 's:\/:\\\/:g'`
    local newt=`echo "$new"| sed 's:\/:\\\/:g'`
    bash <<EOF
echo "$CONTEXT" | sed 's/$oldt/$newt/g'
EOF
cat > 1 <<EOF
 echo "$CONTEXT" | sed 's/$oldt/$newt/g'
EOF
}

# 在文件中替换文本（请不要直接使用此函数）
_file_replace_string(){
    local fin="$1"
    local old="$2"
    local new="$3"
    local oldt=`echo "$old"| sed 's:\/:\\\/:g'`
    local newt=`echo "$new"| sed 's:\/:\\\/:g'`
    echo "sed 's/$oldt/$newt/g' -i $fin"
    if [ "${__replace_no_case_sensitivity}" = "no" ]; then
        bash <<EOF
sed 's/$oldt/$newt/g' -i $fin
EOF
        echo "Replace [$old] to [$new] in [$fin]."
    else
        bash <<EOF
sed 's/$oldt/$newt/gI' -i $fin
EOF
        echo "Replace [$old](ncs) to [$new] in [$fin]."
    fi
}

################################
export  __replace_no_case_sensitivity="no"
# 替换文件内容
## 由于针对是否进行大小写敏感以外的判断都是重复的，因此封装了这样子的函数
__file-replace-string-loop(){
    local fin="$1"
    local old="$2"
    local new="$3"

    if [ ! -f "$fin" -a ! -d "$fin" ] || [ -z "$old" -o -z "$new" ]; then
        echo "$0 file/dir old new"
        return 1
    fi
    if [ -f "$fin" ]; then
        _file_replace_string "$fin" "$old" "$new"
        return
    fi
    if [  -d "$fin" ]; then
        find $fin -type f | grep -v -E "*/.git/" | while read pfile
        do
            _file_replace_string $pfile "$old" "$new"
        done
    fi
}
# 替换文件内容
function file-replace-string(){
    #local fin=$1
    #local old=$2
    #local new=$3
    __replace_no_case_sensitivity=no
    __file-replace-string-loop "$1" "$2" "$3"
}
# 替换文件内容（非大小写敏感）
function file-replace-string-no-case-sensitivity(){
    #local fin=$1
    #local old=$2
    #local new=$3
    __replace_no_case_sensitivity=yes
    __file-replace-string-loop "$1" "$2" "$3"
}
################################

# 替换文件第n行的文件内容
function file-replace-the-line-string(){
    local fin="$1"
    local line="$2"
    local new="$3"
    if [ ! -f "$fin" -o -z "$line" -o -z "$new" ]; then
        echo "$0 file line new"
        return 1
    fi
    local newt=`echo "$new"| sed 's:\/:\\\/:g'`
    bash <<EOF
sed '${line}s/.*/$newt/' -i $fin
EOF
}

# 删除含有关键字的行
function file-delete-match-lines(){
    local fin="$1"
    local old="$2"
    if [ -z "$fin" ]; then
        echo "$0 file keyword"
        return 1
    fi
    local oldt=`echo "$old"| sed 's:\/:\\\/:g'`
    bash <<EOF
sed '/$oldt/d' -i $fin
EOF
}

# 将含有关键字的行整行替换为新的内容
function file-replace-match-lines(){
    local fin=$1
    local old=$2
    local new=$3
    if [ -z "$fin" ]; then
        echo "$0 file old new"
        return 1
    fi
    # 找出匹配的行
    ## cut : -d 用来设置间隔符为冒号， -f 提取所需要的域
    local find_line=`cat $fin | grep -n "$old" |  cut -f1 -d:`
    if [ $? != 0 ];then
        return $?
    fi
    # 考虑到替换的文本可能需要转义，尝试使用不需要转义的符号
    for token in `echo '#' '/'  '!' '@' '|'`
    do
        ret=`echo "$old $new" | grep "$token"`
        if [ ! -z "$ret" ];then
            continue
        fi
        #echo "safe $token"
        # 替换匹配的所有行
        for line in `echo $find_line`
        do
            #sed "${line}s/.*/$new/g" $fin
        bash <<EOF
        sed -i '${line}s${token}.*${token}${new}${token}g' $fin
EOF
        done

        # 替换成功则退出
        if [ $? = 0 ];then
            return
        fi
    done
    #(找不到安全的分隔符)

    # 基于'/'的转义下做的替换
    local oldt=`echo $old| sed 's:\/:\\\/:g'`
    local newt=`echo $new| sed 's:\/:\\\/:g'`

    for line in `echo $find_line`
    do
        bash <<EOF
        sed -i "${line}s/.*/$newt/g" $fin
EOF
    done
}

## 移除Windows的换行符
function file-remove-all-windows-linefeed-at-end-of-lines() {
    local fin="$1"
    local fout="$2"

    if [ -z "$fout" ]; then
        bak $fin
        fout=$fin
    fi
    sed 's///g' $fin > $out.tmp
    mv -f $fout.tmp $fout
}

## 为文件内的每一行尾添加对应的行
function file-append-string-earch-line-end () {
    local file="$1"
    local str="$2"
    if [ ! -f "$1" ]; then
        echo "file string-at-the-end"
        return
    fi
    if [ -z "$1" ]; then
        echo "file string-at-the-end"
        return
    fi
    bash <<EOF
#!/bin/bash
awk '{print \$0"$str"}' $file
EOF
}

## 为文件内的每一行前添加对应的行
function file-append-string-earch-line-begin () {
    local file="$1"
    local str="$2"
    if [ ! -f "$1" ]; then
        echo "file string-at-the-begining"
        return
    fi
    if [ -z "$1" ]; then
        echo "file string-at-the-begining"
        return
    fi
    bash <<EOF
#!/bin/bash
awk '{print "$str"\$0}' $file
EOF
}

## 在文件的匹配行前插入一行
function file-insert-new-line-before-match-line()
{
    local fin="$1"
    local pattern="$2"
    local new_line="$3"
    if [ ! -f "$1" ]; then
        echo "file pattern inserted-line"
        return
    fi
    if [ -z "$pattern" ]; then
        echo "file pattern inserted-line"
        return
    fi
    if [ -z "$new_line" ]; then
        echo "file pattern inserted-line"
        return
    fi
    #bak $fin
    local pattern_t=`echo  "$pattern" | sed 's:\/:\\\/:g'`
    local new_line_t=`echo "$new_line"| sed 's:\/:\\\/:g'`
    bash <<EOF
    sed -i  '/$pattern_t/i\\$new_line_t' $fin
EOF
}

## 在文件的匹配行前插入一行
function file-insert-new-line-after-match-line()
{
    local fin="$1"
    local pattern="$2"
    local new_line="$3"
    if [ ! -f "$1" ]; then
        echo "file pattern inserted-line"
        return
    fi
    if [ -z "$pattern" ]; then
        echo "file pattern inserted-line"
        return
    fi
    if [ -z "$new_line" ]; then
        echo "file pattern inserted-line"
        return
    fi
    #bak $fin
    local pattern_t=`echo  "$pattern"  | sed 's:\/:\\\/:g'`
    local new_line_t=`echo "$new_line"| sed 's:\/:\\\/:g'`
    bash <<EOF
    sed -i  '/$pattern_t/a\\$new_line_t' $fin
EOF
}

## 按要求分割文件(core)
function _file-split-per-xx()
{
    local file="$1"
    local xx="$2"
    split ${xx} -d --additional-suffix=.split $file ${file}. --verbose
}

## 按大小分割文件
function file-split-per-size()
{
    _split_help()
    {
cat <<EOF
$cmd file size(B/K/M/G/T)
e.g.
   $cmd  a.log  10M
   $cmd  a.txt  1K
   $cmd  a.zip  1G
EOF
return 1
    }
    local file="$1"
    local size="$2"
    if [ ! -f "$file" ]; then
        _split_help file-split-per-size
        return
    fi
    if [  -z "$size" ]; then
        _split_help file-split-per-size
        return
    fi
    _file-split-per-xx $file "-b $size" || _split_help
}

## 按行数分割文件
function file-split-per-line()
{
    _split_help()
    {
        cmd="$1"
cat <<EOF
$cmd  file line
e.g.
    $cmd  a.txt  100
EOF
return 1
    }
    local file="$1"
    local line="$2"
    if [ ! -f "$file" ]; then
        _split_help "file-split-per-line"
        return
    fi
    if [ -z "$line" ]; then
        _split_help "file-split-per-line"
        return
    fi
    _file-split-per-xx $file "-l $line" || _split_help "file-split-per-line"
}
